package com.bb.blog.code.mvc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;


/**
 * DispatcherServlet伪代码
 * 用来描述dispatch的流程
 */
public class XDispatcherServlet extends HttpServlet  implements ApplicationContextAware {
    private List<HandlerMapping> handlerMappings;
    private List<HandlerAdapter> handlerAdapters;
    private ApplicationContext applicationContext;
    private Logger logger = LoggerFactory.getLogger(XDispatcherServlet.class);
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        processRequest(req, resp);
    }

    private void processRequest(HttpServletRequest request, HttpServletResponse response) {
        doService(request, response);
    }

    private void doService(HttpServletRequest request, HttpServletResponse response) {
        // 处理参数
        Map<String,Object> attributesSnapshot = new HashMap<String,Object>();
        Enumeration<String> attrNames = request.getAttributeNames();
        while(attrNames.hasMoreElements()){
            String attrName = attrNames.nextElement();
            attributesSnapshot.put(attrName,request.getAttribute(attrName));
        }

        // .... 乱七八糟的东西

        doDispatch(request, response);


    }

    private void doDispatch(HttpServletRequest request, HttpServletResponse response) {
        HttpServletRequest processedRequest = checkMultipart(request);

        try {
            HandlerExecutionChain  handler = getHandler(request);
            if(handler == null){
                throw new RuntimeException("no mapper found for " + request.getMethod() + " " + request.getRequestURI());
            }

            HandlerAdapter ha = getHandlerAdapter(handler.getHandler());
//            for (int i = 0; i < handler.getInterceptorList().size(); i++) {
//                HandlerInterceptor interceptor = handler.getInterceptorList().get(i);
//                if (!interceptor.preHandle(request, response, handler.getHandler())) {
//                    handler.triggerAfterCompletion(request, response, null);
//                }
//            }
            ha.handle(processedRequest,response, handler.getHandler());


        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    private HandlerAdapter getHandlerAdapter(Object handler) {
        if(this.handlerAdapters!=null){
            for (HandlerAdapter adapter : this.handlerAdapters) {
                if(adapter.supports(handler)){
                    return adapter;
                }
            }
        }
        throw new RuntimeException("没有支持的适配器");
    }


    private HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if(this.handlerMappings!= null){
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if(handler!=null){
                    return handler;
                }
            }
        }
        return null;
    }

    private HttpServletRequest checkMultipart(HttpServletRequest request) {
        //是否是multipart的请求，如果是的话需要使用 multipartResolver 进行处理
        // todo 待完善
        return request;
    }

    // 在请求进来的时候才会init
    @Override
    public void init() throws ServletException {
        initMultipartResolver(this.applicationContext);
        initHandlerMappings(this.applicationContext);
        initHandlerAdapters(this.applicationContext);
    }

    private void initHandlerAdapters(ApplicationContext applicationContext) {


    }

    private void initHandlerMappings(ApplicationContext applicationContext) {
        // find all handler mappings
        Map<String, HandlerMapping> matchBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMapping.class, true, false);
        this.handlerMappings =  new ArrayList<>(matchBeans.values());
    }


    private void initMultipartResolver(ApplicationContext applicationContext) {
        Map<String,HandlerAdapter> matchBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerAdapter.class, true, false);
        this.handlerAdapters =  new ArrayList<>(matchBeans.values());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}